package com.group4.highschoolportal.service;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
import com.sun.jersey.api.representation.Form;
import com.sun.jersey.client.urlconnection.HTTPSProperties;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonToken;;

/**
 * SMS client using 46elks REST api
 * You need account at 46elks
 * 
 * @author Andreas
 */
@ManagedBean(name="sms")
@ApplicationScoped
public class RestSmsClient {

    private WebResource webResource;
    private Client client;
    private static final String BASE_URI = "https://api.46elks.com";
    
    //api username and password, should probably be stored in a config somwhere
    private static final String USERNAME = "u40370a2d7c108d5626138cdb78ce1810";
    private static final String PASSWORD = "E202D2ACCA8BFE825B1AC7CABD860B2C";

    public RestSmsClient() {
        ClientConfig config = new DefaultClientConfig(); // SSL configuration
        config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties(getHostnameVerifier(), getSSLContext()));
        client = Client.create(config);
        client.addFilter(new HTTPBasicAuthFilter(USERNAME, PASSWORD));
    }

    /**
     * Sends a sms to with a message to a given number
     * via 46elks REST API
     * 
     * @param to what number to send sms to
     * @param message the message
     */
    public void sendSMS(String to, String message) {
        String[] formParamNames = new String[]{"from", "to", "message"};
        String[] formParamValues = new String[]{fetchFromNumber(), to, message};
        webResource = client.resource(BASE_URI).path("a1/SMS");
        webResource.type(MediaType.APPLICATION_FORM_URLENCODED).post(getQueryOrFormParams(formParamNames, formParamValues));
    }

    private MultivaluedMap getQueryOrFormParams(String[] paramNames, String[] paramValues) {
        MultivaluedMap<String, String> qParams = new Form();
        for (int i = 0; i < paramNames.length; i++) {
            if (paramValues[i] != null) {
                qParams.add(paramNames[i], paramValues[i]);
            }
        }
        return qParams;
    }
    
    /*
     * Just POST to 46elks REST API and fetch the first
     * number available on the account
     */
    private String fetchFromNumber() {

        String fromNumber = null;
        webResource = client.resource(BASE_URI).path("a1/Numbers");
        String resp = webResource.type(MediaType.APPLICATION_FORM_URLENCODED).get(String.class);

        try {

            JsonFactory jfactory = new JsonFactory();
            JsonParser jParser = jfactory.createJsonParser(resp);

            while (jParser.nextToken() != JsonToken.END_OBJECT) {
                String fieldname = jParser.getCurrentName();

                if ("numbers".equals(fieldname)) {
                    jParser.nextToken();
                }

                if ("number".equals(fieldname)) {
                    jParser.nextToken();
                    fromNumber = jParser.getText();
                }
            }
            jParser.close();
        } catch (IOException ex) {
            Logger.getLogger(RestSmsClient.class.getName()).log(Level.SEVERE, null, ex);
        }

        return fromNumber;
    }

    public void close() {
        client.destroy();
    }
    
    /*
     * SSL stuff
     */
    private HostnameVerifier getHostnameVerifier() {
        return new HostnameVerifier() {

            @Override
            public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) {
                return true;
            }
        };
    }

    /**
     * Handling the SSL
     * 
     */
    private SSLContext getSSLContext() {
        javax.net.ssl.TrustManager x509 = new javax.net.ssl.X509TrustManager() {

            @Override
            public void checkClientTrusted(java.security.cert.X509Certificate[] arg0, String arg1) throws java.security.cert.CertificateException {
                return;
            }

            @Override
            public void checkServerTrusted(java.security.cert.X509Certificate[] arg0, String arg1) throws java.security.cert.CertificateException {
                return;
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        SSLContext ctx = null;
        try {
            ctx = SSLContext.getInstance("SSL");
            ctx.init(null, new javax.net.ssl.TrustManager[]{x509}, null);
        } catch (java.security.GeneralSecurityException ex) {
        }
        return ctx;
    }
}
